# -*- coding: utf-8 -*-
from __future__ import print_function, division
#系统库
import types
#第三方库
#自定义库
import local


class Player(object):
    PS_UNKNOWN = 0
    CURRENT_STATE_ID = 1
    __PROPERNAMES = []
    PROPERTIES = []

    PS_NORMAL = 1
    PS_DYING = 2
    PS_DEAD = 3

    @classmethod
    def reg_state(cls, name):
        exec("cls.{0} = {1}".format(name, cls.CURRENT_STATE_ID))
        cls.CURRENT_STATE_ID += 1

    @classmethod
    def reg_prop(cls, propname, proptype):
        if propname in cls.__PROPERNAMES:
            return False
        prop = dict(
            name=propname,
            type=proptype
            )
        cls.__PROPERNAMES.append(propname)
        cls.PROPERTIES.append(prop)

    def __init__(self, u_id, username):
        self.u_id = u_id
        self.username = username

        for prop in Player.PROPERTIES:
            propname = prop['name']
            proptype = prop['type']
            if proptype == types.NoneType:
                exec('self.{0} = None'.format(propname))
            else:
                exec('self.{0} = proptype()'.format(propname))


class Action(object):
    def __init__(self, func, package):
        self.func = func
        self.package = package
        self.available = True

    def switch(self):
        self.available = not self.available

    def action(self, fsm, params):
        self.func(fsm, params)


class Trigger(object):
    def __init__(self, func, num, name=None):
        self.name = func.__name__
        if name:
            self.name = name
        self.func = func
        self.limit_num = num
        self.triggered_num = 0
        self.available = True
        self.triggering = False

    def switch(self):
        self.available = not self.available

    def trigger(self, fsm, params):
        if self.triggering == True:
            return
        self.triggering = True
        self.func(fsm, params)
        self.triggering = False


class Position(object):
    CURRENT_L_ID = 1

    @classmethod
    def reg_position(cls, name):
        exec("Position.{0} = {1}".format(name, Position.CURRENT_L_ID))
        Position.CURRENT_L_ID += 1

    def __init__(self, pos, list_, id_=-1):
        self.pos = pos
        self.list = list_
        self.id = id_


class FSM(object):
    EVENT_BEFORE = 0
    EVENT_AFTER = 2

    PROPERTIES = []
    __PROPERNAMES = []

    FUNCTIONS = {}
    ACTIONS = {}
    TRIGGERS = {}

    @classmethod
    def reg_common(cls, name, value):
        exec("FSM.{0} = {1}".format(name, value))

    @classmethod
    def register_action(cls, event, func, package):
        if event in cls.ACTIONS:
            raise Exception(local.String.FSM_ER_eventexist + cls.ACTIONS[event].package)
        action = Action(func, package)
        cls.ACTIONS[event] = action
        triggers = {}
        triggers[cls.EVENT_BEFORE] = []
        triggers[cls.EVENT_AFTER] = []
        cls.TRIGGERS[event] = triggers
        return

    @classmethod
    def reg_prop(cls, propname, proptype):
        if propname in cls.__PROPERNAMES:
            return
        prop = dict(
            name=propname,
            type=proptype
            )
        cls.__PROPERNAMES.append(propname)
        cls.PROPERTIES.append(prop)
        return

    @classmethod
    def reg_func(cls, funcname, func):
        if funcname in cls.FUNCTIONS:
            return
        cls.FUNCTIONS[funcname] = func
        return

    def __init__(self, room):
        self.room = room
        self.users = room.players
        self.actions = FSM.ACTIONS
        self.triggers = FSM.TRIGGERS
        self.call_stack = []
        #游戏中的玩家情况
        self.players = {}
        #self.playerlist = []
        for user in self.users.values():
            player = Player(user.u_id, user.username)
            self.players[user.u_id] = player
            #self.playerlist.append(player)
        #游戏中其他需要的规则数据
        for prop in FSM.PROPERTIES:
            propname = prop['name']
            proptype = prop['type']
            if proptype == types.NoneType:
                exec('self.{0} = None'.format(propname))
            else:
                exec('self.{0} = proptype()'.format(propname))
        return None

    def register_trigger(self, event, time, func, num, name=None):
        if event not in self.actions:
            raise Exception(local.String.FSM_ER_eventnotexist)
        trigger = Trigger(func, num, name)
        self.triggers[event][time].append(trigger)

    def unregister_trigger(self, event, time, name):
        if event not in self.actions:
            raise Exception(local.String.FSM_ER_eventnotexist)
        for item in filter(lambda x: x.name == name, self.triggers[event][time]):
            self.triggers[event][time].remove(item)

    def on_event(self, event, params):
        if event not in self.actions:
            raise Exception(local.String.FSM_ER_eventnotexist)
        action = dict(
            func=FSM.ACTIONS[event].action,
            params=params
            )
        triggers_before = [dict(
            func=trigger,
            params=params
            ) for trigger in self.triggers[event][FSM.EVENT_BEFORE]]
        triggers_after = [dict(
            func=trigger,
            params=params
            ) for trigger in self.triggers[event][FSM.EVENT_AFTER]]
        self.call_stack.extend(triggers_before)
        self.call_stack.append(action)
        self.call_stack.extend(triggers_after)
        self.run_call_stack()

    def run_call_stack(self):
        while len(self.call_stack) > 0:
            handler = self.call_stack.pop(0)
            handler['func'](self, handler['params'])

    def destroy(self):
        return None

    def call_func(self, name, params):
        func = FSM.FUNCTIONS.get(name)
        if func == None:
            return 10028, local.String.FSM_ER_functionnotexist
        return 0, func(self, params)
